﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using Framework.Core;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using Xunit;

namespace Framework.Tests.Refactoring
{
    public class FindReferencesTest
    {
        public class Toto
        {
            public EnvMode EnvMode { get; set; }
        }

        private static void Resolve(SyntaxTree syntaxTree, AstNode astNode)
        {
            IProjectContent project = new CSharpProjectContent();
            var unresolvedFile = syntaxTree.ToTypeSystem();
            project = project.AddOrUpdateFiles(unresolvedFile);

            var builtInLibs = new Lazy<IList<IUnresolvedAssembly>>(
                delegate
                    {
// ReSharper disable once UnusedVariable
                        Assembly[] assemblies =
                            {
                                typeof (object).Assembly, // mscorlib
                                typeof (Uri).Assembly, // System.dll
                                typeof (Enumerable).Assembly, // System.Core.dll
//					typeof(System.Xml.XmlDocument).Assembly, // System.Xml.dll
//					typeof(System.Drawing.Bitmap).Assembly, // System.Drawing.dll
//					typeof(Form).Assembly, // System.Windows.Forms.dll
                                typeof (EnvMode).Assembly,
                                typeof (IProjectContent).Assembly,
                            };

                        return null;
                    });

            project = project.AddAssemblyReferences(builtInLibs.Value);

            var compilation = project.CreateCompilation();

            var resolver = new CSharpAstResolver(compilation, syntaxTree, unresolvedFile);
            var result = resolver.Resolve(astNode);


            if (result == null)
            {
                Console.WriteLine("Could not find a resolvable node at the caret location.");
            }

            else
            {
                Console.WriteLine(result);
            }
        }

        private static void FindReferences(SyntaxTree syntaxTree, AstNode node)
        {
            IProjectContent project = new CSharpProjectContent();
            var unresolvedFile = syntaxTree.ToTypeSystem();
            project = project.AddOrUpdateFiles(unresolvedFile);
            //project = project.AddAssemblyReferences(builtInLibs.Value);

            var compilation = project.CreateCompilation();
            var resolver = new CSharpAstResolver(compilation, syntaxTree, unresolvedFile);

            IEntity entity;
            var mrr = resolver.Resolve(node) as MemberResolveResult;
            var trr = resolver.Resolve(node) as TypeResolveResult;
            if (mrr != null)
            {
                entity = mrr.Member;
            }
            else if (trr != null)
            {
                entity = trr.Type.GetDefinition();
            }
            else
            {
                return;
            }

            var fr = new FindReferences();
            var referenceCount = 0;
            FoundReferenceCallback callback = delegate(AstNode matchNode, ResolveResult result)
            {
                Console.WriteLine(matchNode.StartLocation + " - " + matchNode + " - " + result);
                referenceCount++;
            };

            var searchScopes = fr.GetSearchScopes(entity);
            Console.WriteLine("Find references to " + entity.ReflectionName);
            fr.FindReferencesInFile(searchScopes, unresolvedFile, syntaxTree, compilation, callback, CancellationToken.None);

            Console.WriteLine("Found " + referenceCount + " references to " + entity.FullName);
        }

        [Fact(Skip = "Not Ready")]
        public void Should_test_find_references()
        {
            const string code = @"
        public class Toto
        {
            public EnvMode EnvMode { get; set; } 
        }
";

            var parser = new CSharpParser();

            var syntaxTree = parser.Parse(code);

            syntaxTree.FileName = "Toto.cs";

// ReSharper disable once UnusedVariable
            var typeDeclaration = syntaxTree.Descendants.First(x => x is TypeDeclaration);
            var simpleType = syntaxTree.Descendants.First(x => x is SimpleType);

            //FindReferences(syntaxTree, type);

            Resolve(syntaxTree, simpleType);
        }
    }
}
